package cn.rengy.tool.excel;

import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import java.util.*;

/**
 * Excel 2010及之后版本采用.xlsx格式，
 * 单张工作表最大行数为1048576行 2的20次方，列数为16384列 2的14次方
 * linux环境 必须 执行 dnf install fontconfig
 */
public class ExcelWriterSheetBuilder {
    private ExcelWriter excelWriter;
    //最大行1048576
    private int rowCount=0;//当前写入行数
    private int maxRowCount=1048576;
    private Map<Integer, HeaderCellObject> headerMap=null;

    /**
     * 设置表头，简单写入SimpleWrite 不需要设置，自动处理
     * Integer->列索引从0开始
     * @param data
     */
    public void setHeaderData(Map<Integer, HeaderCellObject> data){
        this.headerMap=headerMap;
    }

    private SXSSFSheet sheet;
    public ExcelWriterSheetBuilder(ExcelWriter excelWriter) {
        this.excelWriter = excelWriter;
    }

    /**
     *
     * @param sheetName
     * @return
     */
    public ExcelWriterSheetBuilder sheetName(String sheetName) {
        SXSSFWorkbook workbook=excelWriter.getWorkbook();
        if(sheetName==null){
            //linux环境 卡死 执行yum install fontconfig
            sheet = workbook.createSheet();
        }else{
            sheet = workbook.createSheet(sheetName);
        }
        rowCount=0;//重置写入行数
        return this;
    }

    private String getNewSheetName(String oldSheetName){
        //提取数字
        String ss[]=oldSheetName.split("_");
        String oldName=ss[0];
        String newSheetName;
        if(ss.length==1){
            newSheetName=oldName.concat("_").concat("2");
        }else{
            newSheetName=oldName.concat("_").concat(String.valueOf(Integer.parseInt(ss[1])+1));
        }
        return newSheetName;
    }

    CellStyleObject cellStyleObject=CellStyleObject.instance();
    /**
     * 简单写入，不设置格式,传入参数为数据库查询出的原始数据
     *
     * @param dataList
     */
    public void doSimpleWrite(List<Map<String,Object>> dataList) {
        if(dataList==null||dataList.isEmpty()){
            return;
        }
        //1.提取表头
        if(headerMap==null){
            headerMap=new LinkedHashMap<>();
            Map<String,Object> firstRow=dataList.get(0);//取第一行数据
            Iterator<Map.Entry<String,Object>> ite=firstRow.entrySet().iterator();
            int headerCellIndex=0;
            while(ite.hasNext()){
                Map.Entry<String,Object> entry=ite.next();
                String key=entry.getKey();//第一行的数据的key
                HeaderCellObject cellObject=HeaderCellObject.instance(cellStyleObject);
                cellObject.setText(key);
                cellObject.setColumnName(key);
                headerMap.put(headerCellIndex++,cellObject);
            }
        }
        //2.数据转换
        List<Map<Integer, CellObject>> cellList=new ArrayList<>(dataList.size());
        for(int i=0;i<dataList.size();i++){
            Map<String,Object> data=dataList.get(i);
            Map<Integer, CellObject> cell=new LinkedHashMap<>();
            //循环表头写入数据
            Iterator<Map.Entry<Integer,HeaderCellObject>> ite=headerMap.entrySet().iterator();
            while(ite.hasNext()){
                Map.Entry<Integer,HeaderCellObject> entry=ite.next();
                Integer cellIndex=entry.getKey();
                String columnName=entry.getValue().getColumnName();
                Object value=data.get(columnName);
                String text=value==null?null:value.toString();
                CellObject cellObject=CellObject.instance(cellStyleObject).setText(text);
                cell.put(cellIndex,cellObject);
            }
            cellList.add(cell);
        }
        //3.开始写入
        doWrite(cellList);
    }
    /**
     * 超出sheet最大行数自动写入新sheet，
     *
     * @param dataList
     */
    public void doWrite(List<Map<Integer, CellObject>> dataList) {
        if(dataList==null||dataList.isEmpty()){
            return;
        }
        //1.先写表头
        if(rowCount==0&&headerMap!=null){
            List<Map<Integer, CellObject>> headerList=new ArrayList<>(1);
            Map<Integer, CellObject> newHeaderMap=new HashMap<>(headerMap);
            //需要构造新的list，因为write之后会clear
            headerList.add(newHeaderMap);
            //不支持多行表头
            rowCount=1;//更新rowCount
            excelWriter.write(headerList, sheet);
        }
        int afterRowCount=rowCount+dataList.size();
        if(afterRowCount>maxRowCount){
            //总行数大于最大行数，分页保存
            //1.计算剩余可保存行数
            int writeRow=maxRowCount-rowCount;
            if(writeRow>0){
                List<Map<Integer, CellObject>> newList=dataList.subList(0,writeRow);
                rowCount+=writeRow;//更新rowCount
                excelWriter.write(newList, sheet);
                //newList.clear(); //实际不需要，因为write后会执行clear
            }
            //2.写入下个sheet
            String newSheetName=getNewSheetName(sheet.getSheetName());
            //创建新的sheet
            sheetName(newSheetName);
            doWrite(dataList);
        }else{
            rowCount+=dataList.size();//更新rowCount
            excelWriter.write(dataList, sheet);
        }
    }
}
